﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

// using Lcs.TraceVisualiser.Forms.Components;
using Noris.Tools.TraceVisualiser.Support;
using Noris.Tools.TraceVisualiser.TraceData;
using Noris.Tools.TraceVisualiser.Components;
using Noris.Tools.TraceVisualiser.Forms;

namespace Noris.Tools.TraceVisualiser.Green.Client
{
	#region EventItem : data jedné události v trace datech klienta, typicky jde o párovou záležitost (řádky Begin + End v jednom záznamu Event).
	/// <summary>
	/// EventItem : data jedné události v trace datech klienta, typicky jde o párovou záležitost (řádky Begin + End v jednom záznamu Event).
    /// </summary>
    public class EventItem : IEventItem, TraceVisualiser.Forms.IMasterDetails
    {
        #region Vytvoření instance
        /// <summary>
        /// Vytvoří a vrátí instanci objektu odpovídajícího danému vstupnímu řádku.
        /// Nicméně do objektu nic datového nevepisuje, to se provádí voláním metody AddData.
        /// Data v parametru "item" slouží jen k určení konkrétního typu vznikající instance (Class Factory).
        /// </summary>
        /// <param name="stringHeap"></param>
        /// <param name="item"></param>
        /// <returns></returns>
        internal static EventItem CreateEventItem(StringHeap stringHeap, TraceItem item)
        {
            EventItem info = new EventItem(stringHeap, item);
            info.DetectEventForTimeShift(item);
            return info;
        }
        private EventItem(StringHeap stringHeap, TraceItem item)
        {
            this.StringHeap = stringHeap;
            this.Time = TimeRange.Empty;
            this._BooleanValues = 0;
            this.Properties = ElementProperties.Selectable;
            this.CaptionShowAllways = true;
            this.OneDimensional = false;
            this.ContainBegin = false;
            this.ContainEnd = false;
            this.ImagePivotElementPoint = ContentAlignment.MiddleCenter;
            this.ImagePivotImagePoint = ContentAlignment.MiddleCenter;

            this.BackColor = Color.Empty;

            // Už zde musím převzít údaje pro určení ProcessKey a BEDepth (z itemu), protože podle nich se hledá již existující Event (Begin, End) v MainData:
            this.ProcessKeyInt32 = item.ProcessKeyInt32;                               // jeden adresář + datum ze jména souboru
            this.BEDepthInt32 = (item.BSE == LineBSE.System ? 0 : item.BEDepthInt32);  // EventKey
        }
        protected StringHeap StringHeap;
        /// <summary>
        /// Detekce hodnoty do IsEventForTimeShift
        /// </summary>
        /// <param name="item"></param>
        /// <param name="traceInfo"></param>
        /// <returns></returns>
        protected virtual void DetectEventForTimeShift(TraceItem item)
        {
            this.IsEventForTimeShift = false;
            if (item.BSE == LineBSE.System &&
                item.Level == LineIWE.Information &&
                item.UserLength >= 2 &&
                item.Keyword == "Communication" &&
                item.Method == "AsyncRequest" &&
                item.Type == "Interface")
            {
                string sessionId = item.User(0);          // Zde je SessionID, jen bez úvodního znaku "I"
                if (!String.IsNullOrEmpty(sessionId))
                {
                    string user1 = item.User(1);          // Zde je User1, z nichž některé nebudu dohledávat:
                    bool findByUser1 = (!(user1 == "KeepMySession" || user1 == "ResumeThreadAction"));  // Tyto dvě akce nejsou dohledatelné: KeepMySession se pod stejným ActionID opakuje vícekrát, a ResumeThreadAction v serverovém trace nedohledám.
                    if (findByUser1)
                    {
                        string action = item.User(2);     // Zde je ActionID, jde o číslo uložené zatím jako string
                        int actionId;
                        if (Int32.TryParse(action, out actionId))
                        {
                            this.IsEventForTimeShift = true;
                            this.SessionID = sessionId;
                            this.ActionID = actionId;
                        }
                    }
                }
            }
        }
        #endregion
		#region Úložiště boolean hodnot v jednom Int32
        /// <summary>
        /// Vrátí hodnotu Boolean z daného čísla bitu.
        /// Základní třída EventItem nechť využívá bity 0-15, potomek číslo 1 využívá bity 16 - 23, potomek číslo 2 bity 24 - 30.
        /// </summary>
        /// <param name="bite"></param>
        /// <returns></returns>
        protected bool BooleanGet(int bit)
        {
            return ((_BooleanValues & (1 << bit)) > 0);
        }
        /// <summary>
        /// Uloží hodnotu Boolean do daného čísla bitu.
        /// Základní třída EventItem nechť využívá bity 0-15, potomek číslo 1 využívá bity 16 - 23, potomek číslo 2 bity 24 - 30.
        /// </summary>
        /// <param name="bit"></param>
        /// <param name="value"></param>
        protected void BooleanSet(int bit, bool value)
        {
            int mask = 1 << bit;
            if (value)
                _BooleanValues = _BooleanValues | mask;
            else
                _BooleanValues = _BooleanValues & (mask ^ int.MaxValue);
        }
		/// <summary>
		/// Společné úložiště pro hodnoty Bool (jeden bit tohoto Int32 = jedna Bool hodnota
		/// </summary>
        private int _BooleanValues;
        #endregion
        #region Plnění objektu Event z dat objektu Item
        /// <summary>
        /// Do objektu this vepíše data z příchozí události (řádek z trace souboru)
        /// </summary>
        /// <param name="eventEdge"></param>
        /// <param name="traceInfo"></param>
        protected virtual void AddData(IEventEdge eventEdge, TraceInfo traceInfo)
        {
            TraceItem item = eventEdge as TraceItem;
            if (item == null) return;

            switch (item.BSE)
            {
                case LineBSE.System:
                    this.AddDataSystem(item, traceInfo);
                    break;
                case LineBSE.Begin:
                    this.AddDataBegin(item, traceInfo);
                    break;
                case LineBSE.End:
                    this.AddDataEnd(item, traceInfo);
                    break;
            }

            this.PrepareTexts(eventEdge, traceInfo);
        }
        /// <summary>
        /// Do this vloží vstupující data pro událost System
        /// </summary>
        /// <param name="item"></param>
        /// <param name="traceInfo"></param>
        protected virtual void AddDataSystem(TraceItem item, TraceInfo traceInfo)
        {
            // Načtená data:
            this.Time = new Support.TimeRange(item.Time, item.Time);
            this.GCMemoryB = item.GCMemory;
            this.StackBInt32 = item.StackInt32;
            this.AssemblyInt32 = item.AssemblyInt32;
            this.Level = item.Level;
            this.ThreadIdInt32 = item.ThreadIdInt32;
            this.ActiveWindowHandle = item.ActivePageId;
            this.ActivePageId = item.ActivePageId;
            this.TypeInt32 = item.TypeInt32;
            this.MethodInt32 = item.MethodInt32;
            this.KeywordInt32 = item.KeywordInt32;
            this.LineNumberB = item.LineNumber;

            this.UserDataSet(ref this.UserDataS, item.UserDataInt32);

            // Odvozená data:
            this.TargetHomeNode = null;
            this.TargetPaths = new string[] { NorisClientConstants.RootNodeClient + "\\Klient" };
            this.TreePaths = null;
            this.TraceB = traceInfo;

            // Obrázek, zarovnání:
            switch (item.Level)
            {
                case LineIWE.Information:
                    this.ElementImage = null;     // Lcs.TraceVisualiser.Pics.PicLibrary16.Dialoginformation3_Cached;
                    this.HideZeroWidthElementRectangle = false;
                    break;
                case LineIWE.Warning:
                    this.ElementImage = TraceVisualiser.Pics.PicLibrary16.Warning_16_Cached;
                    this.HideZeroWidthElementRectangle = true;
                    break;
                case LineIWE.Error:
                    this.ElementImage = TraceVisualiser.Pics.PicLibrary16.Error_16_Cached;
                    this.HideZeroWidthElementRectangle = true;
                    break;
                case LineIWE.Debug:
                    this.ElementImage = TraceVisualiser.Pics.PicLibrary16.InsertComments_Cached;
                    this.HideZeroWidthElementRectangle = true;
                    break;
            }

            // Barva a viditelnost:
            this.BackColor = Color.LightGreen;
            this.Visible = true;

            // Data daná typem události:
            this.OneDimensional = true;
            this.ContainBegin = true;
            this.ContainEnd = true;
        }
        /// <summary>
        /// Do this vloží vstupující data pro událost Begin
        /// </summary>
        /// <param name="item"></param>
        /// <param name="traceInfo"></param>
        protected virtual void AddDataBegin(TraceItem item, TraceInfo traceInfo)
        {
            // Načtená data:
            this.Time = new TimeRange(item.Time, this.Time.End);
            this.GCMemoryB = item.GCMemory;
            this.StackBInt32 = item.StackInt32;
            this.UserDataSet(ref this.UserDataB, item.UserDataInt32);

            // Společná data pro Begin i End, opsaná z prvního Itemu (ať už je to Begin nebo End):
            this.AddDataFirst(item, traceInfo);

            // Trace a Line:
            this.TraceB = traceInfo;
            this.LineNumberB = item.LineNumber;

            // Barva:
            this.BackColor = Color.LightBlue;
            this.Visible = true;

            // Data daná typem události:
            this.OneDimensional = false;
            this.ContainBegin = true;
        }
        /// <summary>
        /// Do this vloží vstupující data pro událost End
        /// </summary>
        /// <param name="item"></param>
        /// <param name="traceInfo"></param>
        protected virtual void AddDataEnd(TraceItem item, TraceInfo traceInfo)
        {
            // Načtená data:
            this.Time = new Support.TimeRange(this.Time.Begin, item.Time);
            this.GCMemoryE = item.GCMemory;
            this.StackEInt32 = item.StackInt32;
            this.UserDataSet(ref this.UserDataE, item.UserDataInt32);

            // Společná data pro Begin i End, opsaná z prvního Itemu (ať už je to Begin nebo End):
            this.AddDataFirst(item, traceInfo);

            // Trace a Line:
            this.TraceE = traceInfo;
            this.LineNumberE = item.LineNumber;

            // Barva:
            this.BackColor = Color.LightBlue;
            this.Visible = true;

            // Data daná typem události:
            this.OneDimensional = false;
            this.ContainEnd = true;
        }
        /// <summary>
        /// Do this vloží vstupující data společná pro událost Begin a End, ale jen při prvním vstupu
        /// </summary>
        /// <param name="item"></param>
        /// <param name="traceInfo"></param>
        protected virtual void AddDataFirst(TraceItem item, TraceInfo traceInfo)
        {
            if (this.ContainItem) return;

            this.AssemblyInt32 = item.AssemblyInt32;
            this.Level = item.Level;
            this.ThreadIdInt32 = item.ThreadIdInt32;
            this.ActiveWindowHandle = item.ActivePageId;
            this.ActivePageId = item.ActivePageId;
            this.TypeInt32 = item.TypeInt32;
            this.MethodInt32 = item.MethodInt32;
            this.KeywordInt32 = item.KeywordInt32;

            this.TargetHomeNode = null;
            this.TargetPaths = new string[] { NorisClientConstants.RootNodeClient + "\\Klient" };
            this.TreePaths = null;

            this.ContainItem = true;
        }
        /// <summary>
        /// Do cílového pole (target) přenese data ze zdroje (source). Přenáší čistě jen hodnoty Int32 = pointery do StringHeap.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="source"></param>
        protected void UserDataSet(ref int[] target, int[] source)
        {
            target = null;
 	        if (source != null && source.Length > 0)
            {
                target = new Int32[source.Length];
                source.CopyTo(target, 0);
            }
        }
        protected Int32[] UserDataS;
        protected Int32[] UserDataB;
        protected Int32[] UserDataE;
        /// <summary>
        /// Z dat v objektu (a v parametrech) připraví texty do elementu a do tooltipu
        /// </summary>
        /// <param name="eventEdge"></param>
        /// <param name="traceInfo"></param>
        protected virtual void PrepareTexts(IEventEdge eventEdge, TraceInfo traceInfo)
        {
        }
        #endregion
        #region Tvorba textu Caption a Tooltip
        /// <summary>
        /// Vrátí sadu textů pro Captions. Nadřízená metoda si z nich vybere text vhodný pro aktuální velikost elementu.
        /// </summary>
        /// <returns></returns>
        protected virtual string[] CreateCaptions()
        {
            string[] captions = new string[] {
                this.Type,
                this.Type + "." + this.Method + "()",
                this.Assembly + ": " + this.Type + "." + this.Method + "()"
            };

            return captions;
        }
        /// <summary>
        /// Vrátí ToolTip, vždy když je potřeba.
        /// </summary>
        /// <returns></returns>
        protected virtual string CreateToolTipInfo()
        {
            string eol = Environment.NewLine;
            string toolTip = this.Time.StringFullDetail + eol +
                this.Type + "." + this.Method + "()" + eol +
                "Assembly: " + this.Assembly + eol +
                "Keyword: " + this.Keyword + eol +
                "ThreadId: " + this.ThreadId + eol +
                "ActiveWindowHandle: " + this.ActiveWindowHandle + eol +
                "ActivePageId: " + this.ActivePageId + eol +
                "BEDepth: " + this.BEDepth + eol;

            // Trace soubory a číslo řádku:
            toolTip += eol;
            if (this.OneDimensional)
                this.CreateToolTipInfoTrace("TraceFile: ", ref toolTip, this.TraceB, this.LineNumberB);
            else
            {
                this.CreateToolTipInfoTrace("TraceFile.Begin: ", ref toolTip, this.TraceB, this.LineNumberB);
                this.CreateToolTipInfoTrace("TraceFile.End: ", ref toolTip, this.TraceE, this.LineNumberE);
            }

            // UserData
            this.CreateToolTipInfoUser("UserData: ", ref toolTip, this.UserDataS);
            this.CreateToolTipInfoUser("UserData.Begin: ", ref toolTip, this.UserDataB);
            this.CreateToolTipInfoUser("UserData.End: ", ref toolTip, this.UserDataE);

            return toolTip;
        }
        /// <summary>
        /// Do tooltipu přidá texty za trace soubor a číslo řádku
        /// </summary>
        /// <param name="title"></param>
        /// <param name="toolTip"></param>
        /// <param name="traceInfo"></param>
        /// <param name="lineNumber"></param>
        protected virtual void CreateToolTipInfoTrace(string title, ref string toolTip, TraceInfo traceInfo, int lineNumber)
        {
            string eol = Environment.NewLine;
            toolTip += title;
            if (traceInfo == null)
                toolTip += "???" + eol;
            else
                toolTip += traceInfo.FileDirName + "; Line=" + lineNumber.ToString() + eol;
        }
        /// <summary>
        /// Do tooltipu přidá texty za userdata
        /// </summary>
        /// <param name="title"></param>
        /// <param name="toolTip"></param>
        /// <param name="userData"></param>
        protected virtual void CreateToolTipInfoUser(string title, ref string toolTip, int[] userData)
        {
            if (userData == null || userData.Length == 0) return;

            string eol = Environment.NewLine;
            toolTip += eol + title + eol;

            for (int u = 0; u < userData.Length; u++)
                toolTip += "  User" + u.ToString() + ": " + this.StringHeap.GetString(userData[u]) + eol;
        }
        #endregion
        #region Public datové property

        // Data ze souboru
        public TimeRange Time { get; protected set; }
        public int GCMemoryB { get; protected set; }
        public int GCMemoryE { get; protected set; }
        public string StackB { get { return this.StringHeap.GetString(this.StackBInt32); } }
        public Int32 StackBInt32 { get; protected set; }
        public string StackE { get { return this.StringHeap.GetString(this.StackEInt32); } }
        public Int32 StackEInt32 { get; protected set; }
        public string Assembly { get { return this.StringHeap.GetString(this.AssemblyInt32); } }
        public Int32 AssemblyInt32 { get; protected set; }
        public LineIWE Level { get; protected set; }
        public string BEDepth { get { return this.StringHeap.GetString(this.BEDepthInt32); } }
        public Int32 BEDepthInt32 { get; protected set; }
        public string ThreadId { get { return this.StringHeap.GetString(this.ThreadIdInt32); } }
        public Int32 ThreadIdInt32 { get; protected set; }
        public string ProcessKey { get { return this.StringHeap.GetString(this.ProcessKeyInt32); } }
        public Int32 ProcessKeyInt32 { get; protected set; }
        public int ActiveWindowHandle { get; protected set; }
        public int ActivePageId { get; protected set; }
        public string Type { get { return this.StringHeap.GetString(this.TypeInt32); } }
        public Int32 TypeInt32 { get; protected set; }
        public string Method { get { return this.StringHeap.GetString(this.MethodInt32); } }
        public Int32 MethodInt32 { get; protected set; }
        public string Keyword { get { return this.StringHeap.GetString(this.KeywordInt32); } }
        public Int32 KeywordInt32 { get; protected set; }
        
        // Data pro zobrazování
        public int LineNumberB { get; protected set; }
        public int LineNumberE { get; protected set; }
        public string TargetHomeNode { get; protected set; }
        public string[] TargetPaths { get; protected set; }
        public TreePath[] TreePaths { get; protected set; }
        public string ColorGroup { get; protected set; }
        public int ColorIndex { get; protected set; }
        public bool Visible { get { return BooleanGet(0); } protected set { BooleanSet(0, value); } }
        public bool OneDimensional { get { return BooleanGet(1); } protected set { BooleanSet(1, value); } }
        public bool HideZeroWidthElementRectangle { get { return BooleanGet(5); } protected set { BooleanSet(5, value); } }
        public int ElementGroup { get; protected set; }
        public GraphElementShapeType ElementShapeType { get; protected set; }
        public ElementProperties Properties { get; protected set; }
        public Color BackColor { get; protected set; }
        public bool CaptionShowAllways { get { return BooleanGet(6); } protected set { BooleanSet(6, value); } }
        public Image ElementImage { get; protected set; }
        public ContentAlignment ImagePivotElementPoint { get; protected set; }
        public ContentAlignment ImagePivotImagePoint { get; protected set; }
        protected bool ContainBegin { get { return BooleanGet(11); } set { BooleanSet(11, value); } }
        protected bool ContainEnd { get { return BooleanGet(12); } set { BooleanSet(12, value); } }
        protected bool ContainItem { get { return BooleanGet(13); } set { BooleanSet(13, value); } }

        /// <summary>
        /// Reference na objekt Trace, který událost založil, nebo u párových událostí na Trace, který je Begin
        /// </summary>
        public TraceInfo TraceB { get; protected set; }
        /// <summary>
        /// Reference na objekt Trace, ve kterém událost končí. Je vyplněno pouze u párových událostí.
        /// </summary>
        public TraceInfo TraceE { get; protected set; }
        /// <summary>
        /// Jde o událost, která může soužit pro určení TimeShiftu?
        /// </summary>
        public bool IsEventForTimeShift { get; protected set; }
        /// <summary>
        /// SessionID - pouze u událostí, které mají IsEventForTimeShift == true. Pouze číslo, bez úvodního písmena I.
        /// </summary>
        public string SessionID { get; protected set; }
        /// <summary>
        /// ActionID - pouze u událostí, které mají IsEventForTimeShift == true.
        /// </summary>
        public int ActionID { get; protected set; }

        /// <summary>
        /// Vrátí SubTimeSort = číslo trace v čase + číslo řádky
        /// </summary>
        /// <returns></returns>
        private int _GetSubTimeSort()
        {
            // Vrací Int32, který obsahuje bit 31 = 0 (kladné číslo), bity 30 ÷ 25 (6 bitů) = číslo TraceOrder, bity 24 ÷ 0 = číslo LineNumber:
            return (this.TraceB == null ? 0 : (this.TraceB.TraceOrder & 0x003F) << 25) | (this.LineNumberB & 0x00FFFFFF);
        }
        #endregion
        #region IEventPointer Members
        string IEventPointer.ProcessKey { get { return this.ProcessKey; } }
        string IEventPointer.EventKey { get { return this.BEDepth; } }
        int IEventPointer.LineNumber { get { return this.LineNumberB; } }
        #endregion
        #region IEventItem Members
        string IEventItem.MergeKey { get { return null; } }
        string IEventItem.TargetHomeNode { get { return this.TargetHomeNode; } }
        string[] IEventItem.TargetPaths { get { return this.TargetPaths; } }
        TreePath[] IEventItem.TreePaths { get { return this.TreePaths; } }
        TimeRange IEventItem.Time { get { return this.Time; } }
        void IEventItem.AddData(IEventEdge eventEdge, TraceInfo traceInfo)
        {
            this.AddData(eventEdge, traceInfo);
        }
        bool IEventItem.MergeWith(IEventItem nextEventItem) { return false; }
        int IEventItem.ColorIndex { get { return this.ColorIndex; } }
        #endregion
        #region IDataElement Members
        bool IDataElement.ElementVisible { get { return this.Visible; } }
        GID IDataElement.GId { get { return GID.Empty; } }                            // Zde není GID uložen, nemohu jej určit, vrátím Empty. On tento objekt de facto není plnohodnotný IDataElement (právě chybějícím GIDem), ale nechce se mi tvořit jiný interface, shodný s IDataElement až na nepřítomnost GIDu...
        TimeRange IDataElement.TimeRange { get { return this.Time; } set { } }
		float IDataElement.ElementHeightRatio { get { return 0f; } }
		bool IDataElement.BeginIsUncertain { get { return !ContainBegin; } }
        bool IDataElement.EndIsUncertain { get { return !ContainEnd; } }
        int IDataElement.SubTimeSort { get { return _GetSubTimeSort(); } }
        bool IDataElement.FullRow { get { return false; } }
        bool IDataElement.HideZeroWidthElementRectangle { get { return HideZeroWidthElementRectangle; } }
        float[] IDataElement.Fragments { get { return null; } }
        GraphLayerType IDataElement.ElementLayer { get { return GraphLayerType.ElementItemLayer; } }
        int IDataElement.ElementGroup { get { return this.ElementGroup; } }
        GraphElementShapeType IDataElement.ElementShapeType { get { return this.ElementShapeType; } }
        ElementProperties IDataElement.Properties { get { return this.Properties; } }
        ElementActionType IDataElement.ActionOnDoubleClick { get { return ElementActionType.DefaultByRow; } }
        GraphElementHandler IDataElement.DoubleClick { get { return null; } }
        string IDataElement.ColorGroup { get { return this.ColorGroup; } }
		Color IDataElement.BackColor { get { return this.BackColor; } set { this.BackColor = value; } }
        Color IDataElement.FontColor { get { return Color.Empty; } }
        bool IDataElement.CaptionShowAllways { get { return this.CaptionShowAllways; } }
        Image IDataElement.ElementImage { get { return this.ElementImage; } }
        ContentAlignment IDataElement.ImagePivotElementPoint { get { return this.ImagePivotElementPoint; } }
        ContentAlignment IDataElement.ImagePivotImagePoint { get { return this.ImagePivotImagePoint; } }
        string[] IDataElement.Captions { get { return CreateCaptions(); } }
        string IDataElement.ToolTipInfo { get { return CreateToolTipInfo(); } }
        string IDataElement.GetToolTipInfo(IDataRow rowData) { return null; }
        string IDataElement.GetCaption(IDataRow rowData, float charCount) { return null; }
        void IDataElement.DrawElement(GraphElementPainterArgs args) { }
        #endregion
        #region IDisposable Members
        public void Dispose()
        {
            this.StringHeap = null;
        }
        #endregion
        #region IMasterDetails Members
        string IMasterDetails.MasterName { get { return this.Type; } }
        Color IMasterDetails.DetailBackColor { get { return this.BackColor; } }
        public IEnumerable<MasterDetailItem> Details { get { return this.CreateDetails(); } }
        /// <summary>
        /// Vytvoří, naplní a vrátí seznam informací Details.
        /// postupně volá metody DetailFillTraceTime(); DetailFill(); DetailFillUserData();
        /// </summary>
        /// <returns></returns>
        protected virtual IEnumerable<MasterDetailItem> CreateDetails()
        {
            List<MasterDetailItem> result = new List<MasterDetailItem>();

            this.DetailFillTraceTime(result);
            this.DetailFillItems(result);
            this.DetailFillUserData(result);

            return result;
        }
        /// <summary>
        /// Do seznamu detailních údajů vepíše položky ze své evidence.
        /// Třída EventItem vkládá tato data: "Trace, LineNumber"
        /// </summary>
        /// <param name="result"></param>
        protected virtual void DetailFillTraceTime(List<MasterDetailItem> result)
        {
            // Trace, line, time:
            if (this.OneDimensional)
            {
                this.DetailFillTraceInfo("", this.TraceB, this.LineNumberB, result);
                result.Add(new MasterDetailItem("Time", this.Time.Begin.ToString("HH:mm:ss.fff")));
            }
            else
            {
                this.DetailFillTraceInfo(".Begin", this.TraceB, this.LineNumberB, result);
                this.DetailFillTraceInfo(".End", this.TraceE, this.LineNumberE, result);
                result.Add(new MasterDetailItem("Time", this.Time.StringFullDetail));
            }
        }
        /// <summary>
        /// Do sady řádků (detaily) vloží data o daném trace.
        /// </summary>
        /// <param name="title">SubTitulek: například "", ".Begin", ".End" atd</param>
        /// <param name="traceInfo">Objekt TraceInfo. Může být null.</param>
        /// <param name="lineNumber">Číslo řádku. Pokud bude null, nebude se vypisovat.</param>
        /// <param name="result">Seznam řádků, kam se detaily vkládají.</param>
        protected void DetailFillTraceInfo(string title, TraceInfo traceInfo, Int32? lineNumber, List<MasterDetailItem> result)
        {
            if (traceInfo == null)
            {
                result.Add(new MasterDetailItem("Trace" + title, "???"));
            }
            else
            {
                result.Add(new MasterDetailItem("Trace" + title, traceInfo.FullFileName));
                if (lineNumber.HasValue)
                    result.Add(new MasterDetailItem("Trace" + title + ".Line", lineNumber.Value.ToString()));
            }
        }
        /// <summary>
        /// Do seznamu detailních údajů vepíše položky ze své evidence.
        /// Třída EventItem vkládá tato data: "SecureId, BEDepth, StatusInfo, Login, Stack, ThreadId, RoundtripId, PageId, Type, Method, Keyword"
        /// </summary>
        /// <param name="result"></param>
        protected virtual void DetailFillItems(List<MasterDetailItem> result)
        {
            result.Add(new MasterDetailItem("GCMemoryB", this.GCMemoryB));
            result.Add(new MasterDetailItem("GCMemoryE", this.GCMemoryE));
            result.Add(new MasterDetailItem("Stack", this.CreateDetailStack(this.StackB)));

            result.Add(new MasterDetailItem("Level", this.Level.ToString()));
            result.Add(new MasterDetailItem("Assembly", this.Assembly));
            result.Add(new MasterDetailItem("BEDepth", this.BEDepth));
            result.Add(new MasterDetailItem("ThreadId", this.ThreadId));
            result.Add(new MasterDetailItem("ActiveWindowHandle", this.ActiveWindowHandle));
            result.Add(new MasterDetailItem("ActivePageId", this.ActivePageId));
            result.Add(new MasterDetailItem("Keyword", this.Keyword));
            result.Add(new MasterDetailItem("Method", this.Method));
            result.Add(new MasterDetailItem("Type", this.Type));
        }
        /// <summary>
        /// Do seznamu detailních údajů vepíše položky ze své evidence, hodnoty pouze z polí UserData[xxx].
        /// </summary>
        /// <param name="result"></param>
        protected virtual void DetailFillUserData(List<MasterDetailItem> result)
        {
            this.DetailFillUserDataOne("UserData", ref result, this.UserDataS);
            this.DetailFillUserDataOne("UserData.Begin", ref result, this.UserDataB);
            this.DetailFillUserDataOne("UserData.End", ref result, this.UserDataE);
        }
        /// <summary>
        /// Vrátí zformátovaný Stack
        /// </summary>
        /// <param name="stack"></param>
        /// <returns></returns>
        protected virtual string CreateDetailStack(string stack)
        {
            string result = "";
            if (!stack.IsEmpty())
            {
                string[] stackItems = stack.Split('-');
                for (int s = stackItems.Length - 1; s >= 0; s--)
                    result += (result.Length > 0 ? "; " : "") + stackItems[s];
            }
            return result;
        }
        /// <summary>
        /// Do seznamu detailních údajů vepíše položky ze své evidence, hodnoty pouze UserData[xxx].
        /// </summary>
        /// <param name="result"></param>
        protected virtual void DetailFillUserDataOne(string title, ref List<MasterDetailItem> result, Int32[] userData)
        {
            if (userData == null || userData.Length == 0) return;
            for (int u = 0; u < userData.Length; u++)
                result.Add(new MasterDetailItem(title + "[" + u.ToString() + "]", this.StringHeap.GetString(userData[u])));
        } 
        #endregion
    }
    #endregion
}
